using System;
using NUnit.Framework;
using SearchTools.QueryParser;
using System.IO;
using System.Text;

using Lucene.Net.Search;

using CommonAST				= antlr.CommonAST;
using AST					= antlr.collections.AST;
using DumpASTVisitor		= antlr.DumpASTVisitor;
using CharBuffer			= antlr.CharBuffer;
using RecognitionException	= antlr.RecognitionException;
using TokenStreamException	= antlr.TokenStreamException;
using BaseAST				= antlr.BaseAST;
using ASTFactory			= antlr.ASTFactory;
using ASTFrame				= antlr.debug.misc.ASTFrame;

namespace SearchTools.Tests
{
	[TestFixture]
	public class ParserTests
	{
		public static Query  TreeAction(AST t, string[] tokenNames)
		{
			if (t == null)
				return null;

			ASTFactory factory = new ASTFactory();
			AST r = factory.create(0, "AST ROOT");
			r.setFirstChild(t);
			ASTFrame frame = new ASTFrame("QueryLanguage AST", r);
			//frame.ShowDialog();
	
			Query q = null;
			QueryLanguageTreeParser tparse = new QueryLanguageTreeParser();
			try
			{
				q = tparse.query(t);
			}
			catch (RecognitionException e)
			{
				Console.Error.WriteLine(e.Message);
				Console.Error.WriteLine(e.StackTrace);
			}
		
			return q;
		}
		
		private QueryParser.QueryParser MakeParser(string instr)
		{
			StringReader str = new StringReader(instr);
			QueryLexer lexer = new QueryLexer(str);

			QueryParser.QueryParser parser = new QueryParser.QueryParser(lexer);

			return parser;
		}

		private QueryParser.QueryParser ParseQuery(string instr)
		{
			Console.WriteLine("Parsing: " + instr);
			QueryParser.QueryParser parser = MakeParser(instr);
			parser.query();
			CommonAST t = (CommonAST)parser.getAST();
			
			// Print the resulting tree out in LISP notation
			Console.Out.WriteLine(t.ToStringTree());
	
			return parser;
		}


		private Query GenerateQuery(QueryParser.QueryParser parser)
		{
			return TreeAction(parser.getAST(),new string[]{});
		}

		private Query ParseAndGenerate(string q)
		{
			return GenerateQuery(ParseQuery(q));
		}
	
		[Test,Category("Recogniser")]
		public void TestSingleClauseRegognition()
		{
			ParseQuery("field:[from -> to]");
			ParseQuery("field:term");
			ParseQuery("\"Literal Term\"");
			ParseQuery("field:\"Literal Term\"");
			ParseQuery("term");
			ParseQuery("+term");
			ParseQuery("field:term^0.3");
			ParseQuery("field:term~3");
			ParseQuery("field:term^2");
			ParseQuery("\"Escaped Literal Term\"");
			ParseQuery("+(field:term)");
			ParseQuery("(field:term)^2");
		}

		[Test,Category("Recogniser")]
		public void TestCompoundClauseRegognition()
		{
			ParseQuery("term && term");
			ParseQuery("field:term || field:term");
			ParseQuery("field:\"Literal Term\" && field:term");
			ParseQuery("-field:\"Literal Term\" && field:term");
		}

		[Test,Category("Recogniser")]
		public void TestNestedClauseRegognition()
		{
			ParseQuery("field:term || (term && term)");
			ParseQuery("(field:term) || -(field:term && (field:term || term)^2 && (term))");
			ParseQuery("field:\"Literal Term\" && field:term");
			ParseQuery("\"Literal Term\" && field:term");
		}

		[Test,Category("Generator")]
		public void TermQuery()
		{
			Query q = ParseAndGenerate("term~3");
			q = ParseAndGenerate("field:term~3");
			q = ParseAndGenerate("term");
			q = ParseAndGenerate("field:term");
			q = ParseAndGenerate("\"Escaped Literal Term\"");
		}

		[Test,Category("Generator")]
		public void MultipleClauseQuery()
		{
			Query q = ParseAndGenerate("field:term field:term term term term field:term");
		}

		[Test,Category("Generator")]
		public void RangeQuery()
		{
			Query q = ParseAndGenerate("field:[from -> to]");
		}

		[Test,Category("Generator")]
		public void BoostedQuery()
		{
			Query q = ParseAndGenerate("field:term^0.3");

		}

		[Test,Category("Generator")]
		public void NestedQuery()
		{
			Query q = ParseAndGenerate("field:term && (term  && ((term && term) || term))^0.3");

		}

		[Test,Category("Generator")]
		public void BooleanQuery()
		{
			Query q = ParseAndGenerate("field:term && field");
		}

		[Test,Category("Generator")]
		public void UnaryOperator()
		{
			Assert.IsNotNull(ParseAndGenerate("+(field:term && term)"));
		}


		[Test,Category("Generator")]
		public void TestMetaDataInjectionFunction()
		{
			ParseAndGenerate("#injectmeta(provider:key,field)");
		}

	}
}
